www.gusucode.com > VC++ 简易FTP服务器 > VC++ 简易FTP服务器/code/blocksock.cpp
#include "stdafx.h" #include "blocksock.h" IMPLEMENT_DYNAMIC(CBlockingSocketException, CException) CBlockingSocketException::CBlockingSocketException(char* pchMessage) { m_strMessage = pchMessage; m_nError = WSAGetLastError(); } BOOL CBlockingSocketException::GetErrorMessage(LPTSTR lpstrError, UINT nMaxError, PUINT pnHelpContext /*= NULL*/) { char text[200]; if(m_nError == 0) { wsprintf(text, "%s error", (const char*) m_strMessage); } else { wsprintf(text, "%s error #%d", (const char*) m_strMessage, m_nError); } strncpy(lpstrError, text, nMaxError - 1); return TRUE; } IMPLEMENT_DYNAMIC(CBlockingSocket, CObject) void CBlockingSocket::Cleanup() { // doesn't throw an exception because it's called in a catch block if(m_hSocket == NULL) return; VERIFY(closesocket(m_hSocket) != SOCKET_ERROR); m_hSocket = NULL; } bool CBlockingSocket::Create(int nType /* = SOCK_STREAM */) { ASSERT(m_hSocket == NULL); if((m_hSocket = socket(AF_INET, nType, 0)) == INVALID_SOCKET) return false; else return true; } bool CBlockingSocket::Bind(LPCSOCKADDR psa) { ASSERT(m_hSocket != NULL); if(bind(m_hSocket, psa, sizeof(SOCKADDR)) == SOCKET_ERROR) return false; else return true; } bool CBlockingSocket::Listen() { ASSERT(m_hSocket != NULL); if(listen(m_hSocket, 5) == SOCKET_ERROR) return false; else return true; } BOOL CBlockingSocket::Accept(CBlockingSocket& sConnect, LPSOCKADDR psa) { ASSERT(m_hSocket != NULL); ASSERT(sConnect.m_hSocket == NULL); int nLengthAddr = sizeof(SOCKADDR); sConnect.m_hSocket = accept(m_hSocket, psa, &nLengthAddr); if(sConnect == INVALID_SOCKET) { // no exception if the listen was canceled if(WSAGetLastError() != WSAEINTR) { throw new CBlockingSocketException("Accept"); } return FALSE; } return TRUE; } void CBlockingSocket::Close() { if (NULL == m_hSocket) return; if(closesocket(m_hSocket) == SOCKET_ERROR) { // should be OK to close if closed already throw new CBlockingSocketException("Close"); } m_hSocket = NULL; } bool CBlockingSocket::Connect(LPCSOCKADDR psa) { ASSERT(m_hSocket != NULL); // should timeout by itself if(connect(m_hSocket, psa, sizeof(SOCKADDR)) == SOCKET_ERROR) return false; else return true; } int CBlockingSocket::Write(const char* pch, const int nSize, const int nSecs) { int nBytesSent = 0; int nBytesThisTime; const char* pch1 = pch; do { nBytesThisTime = Send(pch1, nSize - nBytesSent, nSecs); nBytesSent += nBytesThisTime; pch1 += nBytesThisTime; } while(nBytesSent < nSize); return nBytesSent; } int CBlockingSocket::Send(const char* pch, const int nSize, const int nSecs) { ASSERT(m_hSocket != NULL); // returned value will be less than nSize if client cancels the reading FD_SET fd = {1, m_hSocket}; TIMEVAL tv = {nSecs, 0}; if(select(0, NULL, &fd, NULL, &tv) == 0) { throw new CBlockingSocketException("Send timeout"); } int nBytesSent; if((nBytesSent = send(m_hSocket, pch, nSize, 0)) == SOCKET_ERROR) { throw new CBlockingSocketException("Send"); } return nBytesSent; } int CBlockingSocket::Receive(char* pch, const int nSize, const int nSecs) { ASSERT(m_hSocket != NULL); FD_SET fd = {1, m_hSocket}; TIMEVAL tv = {nSecs, 0}; if(select(0, &fd, NULL, NULL, &tv) == 0) { throw new CBlockingSocketException("Receive timeout"); } int nBytesReceived; if((nBytesReceived = recv(m_hSocket, pch, nSize, 0)) == SOCKET_ERROR) { throw new CBlockingSocketException("Receive"); } return nBytesReceived; } int CBlockingSocket::ReceiveDatagram(char* pch, const int nSize, LPSOCKADDR psa, const int nSecs) { ASSERT(m_hSocket != NULL); FD_SET fd = {1, m_hSocket}; TIMEVAL tv = {nSecs, 0}; if(select(0, &fd, NULL, NULL, &tv) == 0) { throw new CBlockingSocketException("Receive timeout"); } // input buffer should be big enough for the entire datagram int nFromSize = sizeof(SOCKADDR); int nBytesReceived = recvfrom(m_hSocket, pch, nSize, 0, psa, &nFromSize); if(nBytesReceived == SOCKET_ERROR) { throw new CBlockingSocketException("ReceiveDatagram"); } return nBytesReceived; } int CBlockingSocket::SendDatagram(const char* pch, const int nSize, LPCSOCKADDR psa, const int nSecs) { ASSERT(m_hSocket != NULL); FD_SET fd = {1, m_hSocket}; TIMEVAL tv = {nSecs, 0}; if(select(0, NULL, &fd, NULL, &tv) == 0) { throw new CBlockingSocketException("Send timeout"); } int nBytesSent = sendto(m_hSocket, pch, nSize, 0, psa, sizeof(SOCKADDR)); if(nBytesSent == SOCKET_ERROR) { throw new CBlockingSocketException("SendDatagram"); } return nBytesSent; } void CBlockingSocket::GetPeerAddr(LPSOCKADDR psa) { ASSERT(m_hSocket != NULL); // gets the address of the socket at the other end int nLengthAddr = sizeof(SOCKADDR); if(getpeername(m_hSocket, psa, &nLengthAddr) == SOCKET_ERROR) { throw new CBlockingSocketException("GetPeerName"); } } void CBlockingSocket::GetSockAddr(LPSOCKADDR psa) { ASSERT(m_hSocket != NULL); // gets the address of the socket at this end int nLengthAddr = sizeof(SOCKADDR); if(getsockname(m_hSocket, psa, &nLengthAddr) == SOCKET_ERROR) { throw new CBlockingSocketException("GetSockName"); } } //static CSockAddr CBlockingSocket::GetHostByName(const char* pchName, const USHORT ushPort /* = 0 */) { hostent* pHostEnt = gethostbyname(pchName); if(pHostEnt == NULL) { throw new CBlockingSocketException("GetHostByName"); } ULONG* pulAddr = (ULONG*) pHostEnt->h_addr_list[0]; SOCKADDR_IN sockTemp; sockTemp.sin_family = AF_INET; sockTemp.sin_port = htons(ushPort); sockTemp.sin_addr.s_addr = *pulAddr; // address is already in network byte order return sockTemp; } //static const char* CBlockingSocket::GetHostByAddr(LPCSOCKADDR psa) { hostent* pHostEnt = gethostbyaddr((char*) &((LPSOCKADDR_IN) psa) ->sin_addr.s_addr, 4, PF_INET); if(pHostEnt == NULL) { throw new CBlockingSocketException("GetHostByAddr"); } return pHostEnt->h_name; // caller shouldn't delete this memory } // Class CHttpBlockingSocket IMPLEMENT_DYNAMIC(CHttpBlockingSocket, CBlockingSocket) CHttpBlockingSocket::CHttpBlockingSocket() { m_pReadBuf = new char[nSizeRecv]; m_nReadBuf = 0; } CHttpBlockingSocket::~CHttpBlockingSocket() { delete [] m_pReadBuf; } int CHttpBlockingSocket::ReadHttpHeaderLine(char* pch, const int nSize, const int nSecs) // reads an entire header line through CRLF (or socket close) // inserts zero string terminator, object maintains a buffer { int nBytesThisTime = m_nReadBuf; int nLineLength = 0; char* pch1 = m_pReadBuf; char* pch2; do { // look for lf (assume preceded by cr) if((pch2 = (char*) memchr(pch1 , '\n', nBytesThisTime)) != NULL) { ASSERT((pch2) > m_pReadBuf); ASSERT(*(pch2 - 1) == '\r'); nLineLength = (pch2 - m_pReadBuf) + 1; if(nLineLength >= nSize) nLineLength = nSize - 1; memcpy(pch, m_pReadBuf, nLineLength); // copy the line to caller m_nReadBuf -= nLineLength; memmove(m_pReadBuf, pch2 + 1, m_nReadBuf); // shift remaining characters left break; } pch1 += nBytesThisTime; nBytesThisTime = Receive(m_pReadBuf + m_nReadBuf, nSizeRecv - m_nReadBuf, nSecs); if(nBytesThisTime <= 0) { // sender closed socket or line longer than buffer throw new CBlockingSocketException("ReadHeaderLine"); } m_nReadBuf += nBytesThisTime; } while(TRUE); *(pch + nLineLength) = '\0'; return nLineLength; } int CHttpBlockingSocket::ReadHttpResponse(char* pch, const int nSize, const int nSecs) // reads remainder of a transmission through buffer full or socket close // (assume headers have been read already) { int nBytesToRead, nBytesThisTime, nBytesRead = 0; if(m_nReadBuf > 0) { // copy anything already in the recv buffer memcpy(pch, m_pReadBuf, m_nReadBuf); pch += m_nReadBuf; nBytesRead = m_nReadBuf; m_nReadBuf = 0; } do { // now pass the rest of the data directly to the caller nBytesToRead = min(nSizeRecv, nSize - nBytesRead); nBytesThisTime = Receive(pch, nBytesToRead, nSecs); if(nBytesThisTime <= 0) break; // sender closed the socket pch += nBytesThisTime; nBytesRead += nBytesThisTime; } while(nBytesRead <= nSize); return nBytesRead; } void LogBlockingSocketException(LPVOID pParam, char* pch, CBlockingSocketException* pe) { // pParam holds the HWND for the destination window (in another thread) CString strGmt = CTime::GetCurrentTime().FormatGmt("%m/%d/%y %H:%M:%S GMT"); char text1[200], text2[50]; pe->GetErrorMessage(text2, 49); wsprintf(text1, "WINSOCK ERROR--%s %s -- %s\r\n", pch, text2, (const char*) strGmt); ::SendMessage((HWND) pParam, EM_SETSEL, (WPARAM) 65534, 65535); ::SendMessage((HWND) pParam, EM_REPLACESEL, (WPARAM) 0, (LPARAM) text1); }